package com.uziot.bucket.rest.template.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author shidt
 * @version V1.0
 * @className BizTemplate
 * @date 2020-12-05 22:37:29
 * @description
 */
public abstract class BizTemplate<T> {
    protected String monitorKey;
    protected Logger logger = LoggerFactory.getLogger(getClass());

    public BizTemplate() {
    }

    protected BizTemplate(String monitorKey) {
        this.monitorKey = monitorKey;
    }

    protected abstract void checkParams() throws Exception;

    protected abstract T process() throws Exception;

    protected void afterProcess() {
    }

    protected void onSuccess(T result) {
    }

    /**
     * @return 是否抛出exception, 默认向上抛出
     */
    protected boolean onError(Throwable e) {
        return true;
    }

    /**
     * 如果exception不抛出,需要设定一个默认值
     */
    protected T defaultResult() {
        return null;
    }

    protected boolean isCriticalErrorCode(int errorCode) {
        return false;
    }

    public T execute() throws Exception {
        try {
            checkParams();
        } catch (Exception e) {
            recordInvalidParam(e);
            throw e;
        } catch (Throwable e) {
            recordInvalidParam(e);
        }

        long start = System.currentTimeMillis();
        try {
            T result = process();
            onSuccess(result);
            long time = System.currentTimeMillis() - start;
            logger.info("执行业务逻辑成功: monitorKey={}, time={}", monitorKey, time);
            return result;
        } catch (Exception ex) {
            boolean isThrow = onError(ex);
            if (isThrow) {
                throw ex;
            }
        } catch (Throwable e) {
            boolean isThrow = onError(e);
            logger.error("执行业务逻辑出现未知异常 monitoryKey={}", monitorKey, e);
            if (isThrow) {
                throw e;
            }
        } finally {
            afterProcess();
        }
        return defaultResult();
    }

    private void recordInvalidParam(Throwable e) {
        if (logger.isDebugEnabled()) {
            logger.debug(monitorKey + "_校验参数失败", e);
        } else {
            logger.info(monitorKey + "_校验参数失败: " + e.toString());
        }
    }
}